package com.filestation.backend.service.impl;

import com.filestation.backend.entity.FileInfo;
import com.filestation.backend.repository.FileInfoRepository;
import com.filestation.backend.service.CosService;
import com.filestation.backend.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

import com.filestation.backend.util.ZipUtils;

@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private FileInfoRepository fileInfoRepository;

    @Autowired
    private CosService cosService;

    @Override
    @Transactional
    public FileInfo uploadFile(MultipartFile file, Integer expirationDays, String description, HttpServletRequest request) {
        // 生成唯一文件名
        String originalFilename = file.getOriginalFilename();
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileKey = UUID.randomUUID().toString().replace("-", "") + fileExtension;
        
        // 上传文件到腾讯云COS
        String fileUrl = cosService.uploadFile(file, fileKey);
        
        // 生成6位随机下载码
        String downloadCode = generateDownloadCode();
        
        // 计算过期时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, expirationDays);
        Date expirationTime = calendar.getTime();
        
        // 获取上传IP
        String uploadIp = getClientIp(request);
        
        // 创建文件信息并保存
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(fileKey);
        fileInfo.setOriginalFileName(originalFilename);
        fileInfo.setFileUrl(fileUrl);
        fileInfo.setFileKey(fileKey);
        fileInfo.setFileSize(file.getSize());
        fileInfo.setFileType(file.getContentType());
        fileInfo.setDescription(description);
        fileInfo.setUploadTime(new Date());
        fileInfo.setExpirationTime(expirationTime);
        fileInfo.setDownloadCount(0);
        fileInfo.setUploadIp(uploadIp);
        fileInfo.setDownloadCode(downloadCode);
        fileInfo.setIsDeleted(false);
        
        return fileInfoRepository.save(fileInfo);
    }

    @Override
    public FileInfo getFileByKey(String fileKey) {
        return fileInfoRepository.findByFileKeyAndIsDeletedFalse(fileKey)
                .orElseThrow(() -> new RuntimeException("文件不存在或已删除"));
    }

    @Override
    public FileInfo getFileByDownloadCode(String downloadCode) {
        return fileInfoRepository.findByDownloadCodeAndIsDeletedFalse(downloadCode)
                .orElseThrow(() -> new RuntimeException("下载码无效或已过期"));
    }

    @Override
    @Transactional
    public boolean deleteFile(String fileKey) {
        FileInfo fileInfo = getFileByKey(fileKey);
        
        // 从腾讯云COS删除文件
        boolean deleted = cosService.deleteFile(fileKey);
        
        if (deleted) {
            // 标记为已删除
            fileInfo.setIsDeleted(true);
            fileInfoRepository.save(fileInfo);
        }
        
        return deleted;
    }

    @Override
    @Transactional
    public void incrementDownloadCount(Long fileId) {
        FileInfo fileInfo = fileInfoRepository.findById(fileId)
                .orElseThrow(() -> new RuntimeException("文件不存在"));
        fileInfo.setDownloadCount(fileInfo.getDownloadCount() + 1);
        fileInfoRepository.save(fileInfo);
    }

    @Override
    public List<FileInfo> getAllFiles() {
        return fileInfoRepository.findByIsDeletedFalseOrderByUploadTimeDesc();
    }

    @Override
    @Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
    @Transactional
    public void cleanExpiredFiles() {
        log.info("开始清理过期文件");
        Date now = new Date();
        List<FileInfo> expiredFiles = fileInfoRepository.findExpiredFiles(now);
        
        for (FileInfo fileInfo : expiredFiles) {
            log.info("清理过期文件: {}", fileInfo.getFileKey());
            cosService.deleteFile(fileInfo.getFileKey());
            fileInfo.setIsDeleted(true);
            fileInfoRepository.save(fileInfo);
        }
        
        log.info("过期文件清理完成，共清理{}个文件", expiredFiles.size());
    }
    
    /**
     * 生成6位随机下载码
     */
    private String generateDownloadCode() {
        // 生成6位随机数字
        int randomNum = ThreadLocalRandom.current().nextInt(100000, 1000000);
        return String.valueOf(randomNum);
    }
    
    /**
     * 获取客户端IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP
        if (ip != null && ip.indexOf(",") > 0) {
            ip = ip.substring(0, ip.indexOf(","));
        }
        return ip;
    }

    @Override
    @Transactional
    public FileInfo uploadMultipleFiles(List<MultipartFile> files, String zipName, Integer expirationDays, String description, HttpServletRequest request) {
        if (files == null || files.isEmpty()) {
            throw new RuntimeException("文件列表不能为空");
        }

        try {
            // 生成唯一的压缩文件名
            String zipFileName = (zipName != null && !zipName.trim().isEmpty() ? zipName : "压缩文件") + "_" + System.currentTimeMillis() + ".zip";
            
            // 压缩文件
            File zipFile = ZipUtils.compressToZip(files, zipFileName);
            
            // 生成唯一文件名
            String fileExtension = ".zip";
            String fileKey = UUID.randomUUID().toString().replace("-", "") + fileExtension;
            
            // 上传文件到腾讯云COS
            FileInputStream fileInputStream = FileUtils.openInputStream(zipFile);
            String fileUrl = cosService.uploadFile(fileInputStream, zipFile.length(), "application/zip", fileKey);
            
            // 生成6位随机下载码
            String downloadCode = generateDownloadCode();
            
            // 计算过期时间
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, expirationDays);
            Date expirationTime = calendar.getTime();
            
            // 获取上传IP
            String uploadIp = getClientIp(request);
            
            // 创建文件信息并保存
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(fileKey);
            fileInfo.setOriginalFileName(zipFileName);
            fileInfo.setFileUrl(fileUrl);
            fileInfo.setFileKey(fileKey);
            fileInfo.setFileSize(zipFile.length());
            fileInfo.setFileType("application/zip");
            fileInfo.setDescription(description);
            fileInfo.setUploadTime(new Date());
            fileInfo.setExpirationTime(expirationTime);
            fileInfo.setDownloadCount(0);
            fileInfo.setUploadIp(uploadIp);
            fileInfo.setDownloadCode(downloadCode);
            fileInfo.setIsDeleted(false);
            
            // 删除临时文件
            zipFile.delete();
            
            return fileInfoRepository.save(fileInfo);
        } catch (IOException e) {
            log.error("压缩文件失败", e);
            throw new RuntimeException("压缩文件失败: " + e.getMessage());
        }
    }
} 